home *** CD-ROM | disk | FTP | other *** search
/ Network CD 2 / Network CD - Volume 2.iso / programs / archives / term43_extras.lha / Extras / HydraCom / hydracom-source.lha / amiga.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-20  |  52.4 KB  |  2,480 lines

  1. /*
  2. **    Amiga support module for HYDRA protocol sample implementation.
  3. **
  4. **    Written by    Olaf Barthel
  5. **            Brabeckstrasse 35
  6. **            D-30559 Hannover
  7. **
  8. **            eMail: olsen@sourcery.han.de
  9. **
  10. **    Freely distributable.
  11. */
  12.  
  13.     /* System includes. */
  14.  
  15. #include <intuition/intuitionbase.h>
  16.  
  17. #include <libraries/gadtools.h>
  18. #include <libraries/locale.h>
  19. #include <libraries/asl.h>
  20.  
  21. #include <graphics/gfxbase.h>
  22.  
  23. #include <utility/date.h>
  24.  
  25. #include <devices/conunit.h>
  26. #include <devices/serial.h>
  27. #include <devices/timer.h>
  28.  
  29. #include <hardware/cia.h>
  30.  
  31. #include <dos/dosextens.h>
  32. #include <dos/filehandler.h>
  33. #include <dos/dostags.h>
  34. #include <dos/dosasl.h>
  35.  
  36. #include <exec/memory.h>
  37.  
  38.     /* Correct a nasty bug in the prototypes. */
  39.  
  40. #define CheckIO foo21234
  41.  
  42. #include <clib/intuition_protos.h>
  43. #include <clib/gadtools_protos.h>
  44. #include <clib/graphics_protos.h>
  45. #include <clib/utility_protos.h>
  46. #include <clib/locale_protos.h>
  47. #include <clib/timer_protos.h>
  48. #include <clib/exec_protos.h>
  49. #include <clib/dos_protos.h>
  50. #include <clib/asl_protos.h>
  51. #include <clib/macros.h>
  52.  
  53. #include <errno.h>
  54.  
  55.     /* Get the CheckIO prototype right. */
  56.  
  57. #undef CheckIO
  58.  
  59. struct IORequest *CheckIO(struct IORequest *);
  60.  
  61. #include "Rendezvous.h"
  62.  
  63. #include "hydracom.h"
  64.  
  65.     /* Difference between UTC and Amiga time. */
  66.  
  67. #define UTC_OFFSET    252482400
  68.  
  69.     /* Minimum of lines to reserve for local input. */
  70.  
  71. #define MIN_LINES    3
  72.  
  73.     /* Serial buffer size. */
  74.  
  75. #define BUFFER_SIZE    8192
  76.  
  77.     /* A handy macro. */
  78.  
  79. #define ClrSignal(s)    SetSignal(0,s)
  80.  
  81.     /* Signal masks. */
  82.  
  83. #define SIG_SERREAD    (1UL << ReadPort -> mp_SigBit)
  84. #define SIG_SERWRITE    (1UL << WritePort -> mp_SigBit)
  85. #define SIG_CONREAD    (1UL << ConsoleReadPort -> mp_SigBit)
  86. #define SIG_TIMER    (1UL << TimePort -> mp_SigBit)
  87. #define SIG_WINDOW    (1UL << LocalWindow -> UserPort -> mp_SigBit)
  88. #define SIG_HANDSHAKE    SIGF_SINGLE
  89. #define SIG_KILL    SIGBREAKF_CTRL_C
  90.  
  91.     /* A serial buffer structure. */
  92.  
  93. struct SerialBuffer
  94. {
  95.     struct IOExtSer    *SerialRequest;
  96.     UBYTE        *SerialBuffer,
  97.             *SerialIndex,
  98.             *SerialTop;
  99.     LONG         SerialSize,
  100.              SerialFilled;
  101.     BOOL         IsClone,
  102.              IsBusy;
  103. };
  104.  
  105.     /* Special rendezvous data. */
  106.  
  107. STATIC struct RendezvousData        *RendezvousData;
  108. STATIC struct RendezvousSemaphore    *RendezvousSemaphore;
  109.  
  110.     /* Library bases. */
  111.  
  112. struct IntuitionBase    *IntuitionBase;
  113. struct GfxBase        *GfxBase;
  114. struct LocaleBase    *LocaleBase;
  115. struct Library        *GadToolsBase,
  116.             *UtilityBase,
  117.             *TimerBase,
  118.             *AslBase;
  119.  
  120.     /* Timer data. */
  121.  
  122. struct MsgPort        *TimePort;
  123. struct timerequest    *TimeRequest;
  124.  
  125.     /* Serial data. */
  126.  
  127. struct MsgPort        *ReadPort,
  128.             *WritePort;
  129.  
  130. struct SerialBuffer    *ThisBuffer,
  131.             *NextBuffer,
  132.             *ReadBuffer;
  133.  
  134.     /* Console data. */
  135.  
  136. struct Window        *FileWindow,
  137.             *RemoteWindow,
  138.             *LocalWindow,
  139.             *LogWindow;
  140.  
  141. struct MsgPort        *ConsoleWritePort,
  142.             *ConsoleReadPort;
  143. struct IOStdReq        *ConsoleReadRequest;
  144. UBYTE             ConsoleChar;
  145. BOOL             ConsoleReady = FALSE,
  146.              WindowReady = FALSE;
  147.  
  148. struct IOStdReq        *FileRequest,
  149.             *RemoteRequest,
  150.             *LocalRequest,
  151.             *LogRequest;
  152.  
  153.     /* DOS Data. */
  154.  
  155. struct Process        *ThisProcess;
  156. APTR             OldPtr;
  157.  
  158. struct AnchorPath    *Anchor;
  159. BOOL             AnchorUsed = FALSE;
  160.  
  161.     /* File requester data. */
  162.  
  163. struct Process        *FileRequesterProcess;
  164. struct MsgPort        *FileRequesterPort;
  165.  
  166.     /* Screen data. */
  167.  
  168. struct Screen        *PublicScreen,
  169.             *Screen;
  170.  
  171.     /* Menu data. */
  172.  
  173. APTR             VisualInfo;
  174. struct Menu        *Menu;
  175.  
  176. struct NewMenu MenuTemplate[] =
  177. {
  178.     { NM_TITLE, "Project",             0 ,    0,    0,    (APTR)0},
  179.     {  NM_ITEM, "Toggle chat",        "C",    0,    0,    (APTR)Alt_C},
  180.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  181.     {  NM_ITEM, "Hang up",            "H",    0,    0,    (APTR)Alt_H},
  182.     {  NM_ITEM, "Toggle duplex",        "E",    0,    0,    (APTR)Alt_E},
  183.     {  NM_ITEM, "Toggle 7 bits/8 bits",    "B",    0,    0,    (APTR)Alt_B},
  184.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  185.     {  NM_ITEM, "Start upload",        "U",    0,    0,    (APTR)PgUp},
  186.     {  NM_ITEM, "Start download",        "D",    0,    0,    (APTR)PgDn},
  187.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  188.     {  NM_ITEM, "Abort Hydra session",    ".",    0,    0,    (APTR)Esc},
  189.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  190.     {  NM_ITEM, "Exit HydraCom",        "Q",    0,    0,    (APTR)Alt_X},
  191.     { NM_END,   0,                 0 ,    0,    0,    (APTR)0}
  192. };
  193.  
  194.     /* Time data. */
  195.  
  196. LONG             GMT_Offset = UTC_OFFSET;
  197.  
  198.     /* Version ID. */
  199.  
  200. STRPTR VersionTag = "$VER: hydracom 1.0r5 (25.1.95)\r\n";
  201.  
  202.     /* UpdateTime(struct timeval *Now):
  203.      *
  204.      *    Get the current time and/or update the current
  205.      *    time offset data.
  206.      */
  207.  
  208. STATIC VOID __regargs
  209. UpdateTime(struct timeval *Now)
  210. {
  211.     if(Now)
  212.         Now -> tv_secs = Now -> tv_micro = 0;
  213.  
  214.     if(TimePort = CreateMsgPort())
  215.     {
  216.         if(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest)))
  217.         {
  218.             if(!OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  219.             {
  220.                 TimerBase = (struct Library *)TimeRequest -> tr_node . io_Device;
  221.  
  222.                 if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  223.                 {
  224.                     struct Locale *Locale;
  225.  
  226.                     if(Locale = OpenLocale(NULL))
  227.                     {
  228.                         GMT_Offset = 60 * Locale -> loc_GMTOffset + UTC_OFFSET;
  229.  
  230.                         CloseLocale(Locale);
  231.                     }
  232.  
  233.                     CloseLibrary(LocaleBase);
  234.  
  235.                     LocaleBase = NULL;
  236.                 }
  237.  
  238.                 if(Now)
  239.                     GetSysTime(Now);
  240.  
  241.                 TimerBase = NULL;
  242.  
  243.                 CloseDevice(TimeRequest);
  244.             }
  245.  
  246.             DeleteIORequest(TimeRequest);
  247.  
  248.             TimeRequest = NULL;
  249.         }
  250.  
  251.         DeleteMsgPort(TimePort);
  252.  
  253.         TimePort = NULL;
  254.     }
  255. }
  256.  
  257.     /* FileRequestEntry(VOID):
  258.      *
  259.      *    Asynchronous file request process entry.
  260.      */
  261.  
  262. STATIC VOID __saveds
  263. FileRequestEntry(VOID)
  264. {
  265.     struct FileRequester *FileRequester;
  266.  
  267.     if(FileRequester = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
  268.         ASLFR_TitleText,    "Select file(s) to upload",
  269.         ASLFR_InitialPattern,    "#?",
  270.         ASLFR_Flags1,        FRF_PRIVATEIDCMP | FRF_DOMULTISELECT | FRF_DOPATTERNS,
  271.     TAG_DONE))
  272.     {
  273.         if(FileRequesterPort = CreateMsgPort())
  274.         {
  275.             struct Message    *Message;
  276.             ULONG         Signals;
  277.             BOOL         Done = FALSE;
  278.  
  279.             FileRequesterProcess = (struct Process *)FindTask(NULL);
  280.  
  281.             Signal(ThisProcess,SIG_HANDSHAKE);
  282.  
  283.             do
  284.             {
  285.                 Signals = Wait((1L << FileRequesterPort -> mp_SigBit) | SIG_KILL);
  286.  
  287.                 if(Signals & (1L << FileRequesterPort -> mp_SigBit))
  288.                 {
  289.                     LONG MaxLen;
  290.  
  291.                     while(Message = GetMsg(FileRequesterPort))
  292.                     {
  293.                         MaxLen = (LONG)Message -> mn_Node . ln_Name;
  294.  
  295.                         if(AslRequestTags(FileRequester,
  296.                             ASLFR_Window,        LocalWindow,
  297.                             ASLFR_SleepWindow,    TRUE,
  298.                         TAG_DONE))
  299.                         {
  300.                             if(FileRequester -> fr_NumArgs > 0)
  301.                             {
  302.                                 UBYTE     LocalBuffer[256];
  303.                                 char    *String;
  304.                                 LONG     Len,Count,i;
  305.  
  306.                                 for(i = Len = 0 ; i < FileRequester -> fr_NumArgs ; i++)
  307.                                 {
  308.                                     if(FileRequester -> fr_ArgList[i] . wa_Lock)
  309.                                     {
  310.                                         if(NameFromLock(FileRequester -> fr_ArgList[i] . wa_Lock,LocalBuffer,256))
  311.                                             Len += strlen(LocalBuffer) + 1;
  312.                                     }
  313.                                     else
  314.                                         Len += strlen(FileRequester -> fr_Drawer) + 1;
  315.  
  316.                                     Len += strlen(FileRequester -> fr_ArgList[i] . wa_Name) + 1;
  317.                                 }
  318.  
  319.                                 Len++;
  320.  
  321.                                 if(String = AllocVec(Len,MEMF_ANY))
  322.                                 {
  323.                                     *String = 0;
  324.  
  325.                                     for(i = Count = 0 ; Count < MaxLen && i < FileRequester -> fr_NumArgs ; i++)
  326.                                     {
  327.                                         if(FileRequester -> fr_ArgList[i] . wa_Lock)
  328.                                         {
  329.                                             if(NameFromLock(FileRequester -> fr_ArgList[i] . wa_Lock,LocalBuffer,256))
  330.                                             {
  331.                                                 if(AddPart(LocalBuffer,FileRequester -> fr_ArgList[i] . wa_Name,256))
  332.                                                 {
  333.                                                     if(Count + strlen(LocalBuffer) < MaxLen)
  334.                                                     {
  335.                                                         strcat(String,LocalBuffer);
  336.  
  337.                                                         Count += strlen(LocalBuffer);
  338.                                                     }
  339.                                                     else
  340.                                                         break;
  341.                                                 }
  342.                                             }
  343.                                         }
  344.                                         else
  345.                                         {
  346.                                             strcpy(LocalBuffer,FileRequester -> fr_Drawer);
  347.  
  348.                                             if(AddPart(LocalBuffer,FileRequester -> fr_ArgList[i] . wa_Name,256))
  349.                                             {
  350.                                                 if(Count + strlen(LocalBuffer) < MaxLen)
  351.                                                 {
  352.                                                     strcat(String,LocalBuffer);
  353.  
  354.                                                     Count += strlen(LocalBuffer);
  355.                                                 }
  356.                                                 else
  357.                                                     break;
  358.                                             }
  359.                                         }
  360.  
  361.                                         if(i != FileRequester -> fr_NumArgs - 1)
  362.                                         {
  363.                                             strcat(String," ");
  364.                                             Count++;
  365.                                         }
  366.                                     }
  367.  
  368.                                     Message -> mn_Node . ln_Name = String;
  369.  
  370.                                     ReplyMsg(Message);
  371.  
  372.                                     Message = NULL;
  373.                                 }
  374.                             }
  375.                             else
  376.                             {
  377.                                 if(FileRequester -> fr_File[0])
  378.                                 {
  379.                                     LONG Len;
  380.  
  381.                                     Len = strlen(FileRequester -> fr_Drawer) + strlen(FileRequester -> fr_File) + 2;
  382.  
  383.                                     if(Len <= MaxLen)
  384.                                     {
  385.                                         char *String;
  386.  
  387.                                         if(String = AllocVec(Len,MEMF_ANY))
  388.                                         {
  389.                                             strcpy(String,FileRequester -> fr_Drawer);
  390.  
  391.                                             if(AddPart(String,FileRequester -> fr_File,Len))
  392.                                             {
  393.                                                 Message -> mn_Node . ln_Name = String;
  394.  
  395.                                                 ReplyMsg(Message);
  396.  
  397.                                                 Message = NULL;
  398.                                             }
  399.                                             else
  400.                                                 FreeVec(String);
  401.                                         }
  402.                                     }
  403.                                 }
  404.                             }
  405.                         }
  406.  
  407.                         if(Message)
  408.                         {
  409.                             Message -> mn_Node . ln_Name = NULL;
  410.  
  411.                             ReplyMsg(Message);
  412.                         }
  413.                     }
  414.                 }
  415.  
  416.                 if(Signals & SIG_KILL)
  417.                     Done = TRUE;
  418.             }
  419.             while(!Done);
  420.  
  421.             while(Message = GetMsg(FileRequesterPort))
  422.             {
  423.                 Message -> mn_Node . ln_Name = NULL;
  424.  
  425.                 ReplyMsg(Message);
  426.             }
  427.  
  428.             DeleteMsgPort(FileRequesterPort);
  429.         }
  430.  
  431.         FreeAslRequest(FileRequester);
  432.     }
  433.  
  434.     Forbid();
  435.  
  436.     FileRequesterProcess = NULL;
  437.  
  438.     Signal(ThisProcess,SIG_HANDSHAKE);
  439. }
  440.  
  441.     /* GetFiles(char *Buffer,int MaxLen):
  442.      *
  443.      *    Get a list of file names, asynchronously please.
  444.      */
  445.  
  446. char *
  447. GetFiles(char *Buffer,int MaxLen)
  448. {
  449.     struct MsgPort    *ReplyPort;
  450.     char        *Result = NULL;
  451.  
  452.     if(ReplyPort = CreateMsgPort())
  453.     {
  454.         struct Message *Message;
  455.  
  456.         if(Message = AllocVec(sizeof(struct Message),MEMF_ANY | MEMF_CLEAR))
  457.         {
  458.             Message -> mn_Length        = sizeof(struct Message);
  459.             Message -> mn_ReplyPort        = ReplyPort;
  460.             Message -> mn_Node . ln_Name    = (STRPTR)MaxLen;
  461.  
  462.             PutMsg(FileRequesterPort,Message);
  463.  
  464.             FOREVER
  465.             {
  466.                 if(SetSignal(0,(1L << ReplyPort -> mp_SigBit)) & (1L << ReplyPort -> mp_SigBit))
  467.                 {
  468.                     GetMsg(ReplyPort);
  469.  
  470.                     break;
  471.                 }
  472.  
  473.                 sys_idle();
  474.             }
  475.  
  476.             if(Message -> mn_Node . ln_Name)
  477.             {
  478.                 strcpy(Buffer,Message -> mn_Node . ln_Name);
  479.  
  480.                 FreeVec(Message -> mn_Node . ln_Name);
  481.  
  482.                 Result = Buffer;
  483.             }
  484.  
  485.             FreeVec(Message);
  486.         }
  487.  
  488.         DeleteMsgPort(ReplyPort);
  489.     }
  490.  
  491.     return(Result);
  492. }
  493.  
  494.     /* OpenConsole():
  495.      *
  496.      *    Open a console window.
  497.      */
  498.  
  499. STATIC BOOL __inline
  500. OpenConsole(struct Screen *Screen,LONG Top,LONG Height,STRPTR Title,BOOL Resize,struct Window **WindowPtr,struct IOStdReq **ConsolePtr)
  501. {
  502.     struct Window *Window;
  503.  
  504.     if(Window = OpenWindowTags(NULL,
  505.         WA_Left,        0,
  506.         WA_Top,            Top,
  507.         WA_Width,        Screen -> Width,
  508.         WA_Height,        Height,
  509.         WA_Title,        Title,
  510.         WA_SimpleRefresh,    TRUE,
  511.         WA_DepthGadget,        TRUE,
  512.         WA_DragBar,        TRUE,
  513.         WA_SizeGadget,        Resize,
  514.         WA_SizeBRight,        TRUE,
  515.         WA_CustomScreen,    Screen,
  516.         WA_RMBTrap,        TRUE,
  517.         WA_NewLookMenus,    TRUE,
  518.     TAG_DONE))
  519.     {
  520.         struct IOStdReq *ConsoleRequest;
  521.  
  522.         if(Window -> RPort -> Font -> tf_Flags & FPF_PROPORTIONAL)
  523.             SetFont(Window -> RPort,GfxBase -> DefaultFont);
  524.  
  525.         if(ConsoleRequest = (struct IOStdReq *)CreateIORequest(ConsoleWritePort,sizeof(struct IOStdReq)))
  526.         {
  527.             ConsoleRequest -> io_Data = Window;
  528.  
  529.             if(!OpenDevice("console.device",CONU_CHARMAP,ConsoleRequest,CONFLAG_DEFAULT))
  530.             {
  531.                 WindowLimits(Window,Window -> BorderLeft + 10 * Window -> RPort -> Font -> tf_XSize * 10 + Window -> BorderRight,Window -> BorderTop + 2 * Window -> RPort -> Font -> tf_YSize + Window -> BorderBottom,Screen -> Width,Screen -> Height);
  532.  
  533.                     /* Turn off the cursor. */
  534.  
  535.                 ConPrintf(ConsoleRequest,"\033[0 p");
  536.  
  537.                 *WindowPtr    = Window;
  538.                 *ConsolePtr    = ConsoleRequest;
  539.  
  540.                 return(TRUE);
  541.             }
  542.  
  543.             DeleteIORequest(ConsoleRequest);
  544.         }
  545.  
  546.         CloseWindow(Window);
  547.     }
  548.  
  549.     return(FALSE);
  550. }
  551.  
  552.     /* CloseConsole():
  553.      *
  554.      *    Close a console window.
  555.      */
  556.  
  557. STATIC VOID __inline
  558. CloseConsole(struct Window **WindowPtr,struct IOStdReq **ConsolePtr)
  559. {
  560.     if(*ConsolePtr)
  561.     {
  562.         CloseDevice(*ConsolePtr);
  563.  
  564.         DeleteIORequest(*ConsolePtr);
  565.  
  566.         *ConsolePtr = NULL;
  567.     }
  568.  
  569.     if(*WindowPtr)
  570.     {
  571.         CloseWindow(*WindowPtr);
  572.  
  573.         *WindowPtr = NULL;
  574.     }
  575. }
  576.  
  577.     /* CloneSerialBuffer():
  578.      *
  579.      *    Clone a SerialBuffer structure.
  580.      */
  581.  
  582. STATIC struct SerialBuffer * __regargs
  583. CloneSerialBuffer(struct SerialBuffer *Source,struct MsgPort *MsgPort)
  584. {
  585.     struct SerialBuffer *Buffer;
  586.  
  587.     if(Buffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + Source -> SerialSize,MEMF_ANY | MEMF_PUBLIC))
  588.     {
  589.         Buffer -> SerialBuffer    = Buffer -> SerialIndex = (UBYTE *)(Buffer + 1);
  590.         Buffer -> SerialFilled    = 0;
  591.         Buffer -> SerialTop    = Buffer -> SerialBuffer + Source -> SerialSize;
  592.         Buffer -> SerialSize    = Source -> SerialSize;
  593.         Buffer -> IsClone    = TRUE;
  594.         Buffer -> IsBusy    = FALSE;
  595.  
  596.         if(Buffer -> SerialRequest = (struct IOExtSer *)AllocVec(sizeof(struct IOExtSer),MEMF_ANY | MEMF_PUBLIC))
  597.         {
  598.             CopyMem(Source -> SerialRequest,Buffer -> SerialRequest,sizeof(struct IOExtSer));
  599.  
  600.             Buffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = MsgPort;
  601.  
  602.             return(Buffer);
  603.         }
  604.         else
  605.             cprint("Could not create serial request\n");
  606.  
  607.         FreeVec(Buffer);
  608.     }
  609.     else
  610.         cprint("Could not create serial buffer\n");
  611.  
  612.     return(NULL);
  613. }
  614.  
  615.     /* DeleteSerialBuffer():
  616.      *
  617.      *    Delete a SerialBuffer structure.
  618.      */
  619.  
  620. STATIC VOID __regargs
  621. DeleteSerialBuffer(struct SerialBuffer *Buffer)
  622. {
  623.     if(Buffer)
  624.     {
  625.         if(Buffer -> IsBusy)
  626.         {
  627.             if(!CheckIO(Buffer -> SerialRequest))
  628.                 AbortIO(Buffer -> SerialRequest);
  629.  
  630.             WaitIO(Buffer -> SerialRequest);
  631.         }
  632.  
  633.         if(Buffer -> IsClone)
  634.             FreeVec(Buffer -> SerialRequest);
  635.         else
  636.         {
  637.             CloseDevice(Buffer -> SerialRequest);
  638.  
  639.             DeleteIORequest(Buffer -> SerialRequest);
  640.         }
  641.  
  642.         FreeVec(Buffer);
  643.     }
  644. }
  645.  
  646.     /* CreateSerialBuffer():
  647.      *
  648.      *    Create a serial buffer structure.
  649.      */
  650.  
  651. STATIC struct SerialBuffer * __regargs
  652. CreateSerialBuffer(STRPTR Device,LONG Unit,LONG Size,struct MsgPort *MsgPort)
  653. {
  654.     struct SerialBuffer *Buffer;
  655.  
  656.     if(Buffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + Size,MEMF_ANY | MEMF_PUBLIC))
  657.     {
  658.         Buffer -> SerialBuffer    = Buffer -> SerialIndex = (UBYTE *)(Buffer + 1);
  659.         Buffer -> SerialFilled    = 0;
  660.         Buffer -> SerialTop    = Buffer -> SerialBuffer + Size;
  661.         Buffer -> SerialSize    = Size;
  662.         Buffer -> IsClone    = FALSE;
  663.         Buffer -> IsBusy    = FALSE;
  664.  
  665.         if(Buffer -> SerialRequest = (struct IOExtSer *)CreateIORequest(MsgPort,sizeof(struct IOExtSer)))
  666.         {
  667.             Buffer -> SerialRequest -> io_SerFlags = SERF_SHARED;
  668.  
  669.             if(!OpenDevice(Device,Unit,Buffer -> SerialRequest,NULL))
  670.                 return(Buffer);
  671.             else
  672.             {
  673.                 cprint("Could not open \"%s\", unit %d\n",Device,Unit);
  674.  
  675.                 DeleteIORequest(Buffer -> SerialRequest);
  676.             }
  677.         }
  678.         else
  679.             cprint("Could not create serial request\n");
  680.  
  681.         FreeVec(Buffer);
  682.     }
  683.     else
  684.         cprint("Could not create serial buffer\n");
  685.  
  686.     return(NULL);
  687. }
  688.  
  689.     /* OpenAll():
  690.      *
  691.      *    Allocate all the resources required.
  692.      */
  693.  
  694. STATIC BOOL
  695. OpenAll(STRPTR Device,LONG Unit)
  696. {
  697.     LONG Top,Lines,BorderSize,FontSize,ExtraLines,RemainingLines,TotalHeight;
  698.     UWORD Pens = (UWORD)~0;
  699.  
  700.     ThisProcess = (struct Process *)FindTask(NULL);
  701.  
  702.     if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37)))
  703.     {
  704.         cprint("Could not open intuition.library v37\n");
  705.  
  706.         return(FALSE);
  707.     }
  708.  
  709.     if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",37)))
  710.     {
  711.         cprint("Could not open graphics.library v37\n");
  712.  
  713.         return(FALSE);
  714.     }
  715.  
  716.     if(!(GadToolsBase = OpenLibrary("gadtools.library",37)))
  717.     {
  718.         cprint("Could not open gadtools.library v37\n");
  719.  
  720.         return(FALSE);
  721.     }
  722.  
  723.     if(!(UtilityBase = OpenLibrary("utility.library",37)))
  724.     {
  725.         cprint("Could not open utility.library v37\n");
  726.  
  727.         return(FALSE);
  728.     }
  729.  
  730.     if(!(AslBase = OpenLibrary("asl.library",37)))
  731.     {
  732.         cprint("Could not open asl.library v37\n");
  733.  
  734.         return(FALSE);
  735.     }
  736.  
  737.     if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  738.     {
  739.         struct Locale *Locale;
  740.  
  741.         if(Locale = OpenLocale(NULL))
  742.         {
  743.             GMT_Offset = 60 * Locale -> loc_GMTOffset + UTC_OFFSET;
  744.  
  745.             CloseLocale(Locale);
  746.         }
  747.  
  748.         CloseLibrary(LocaleBase);
  749.     }
  750.  
  751.     Forbid();
  752.  
  753.     if(CreateNewProcTags(
  754.         NP_Name,    "HydraCom Filerequester Process",
  755.         NP_WindowPtr,    -1,
  756.         NP_Entry,    FileRequestEntry,
  757.     TAG_DONE))
  758.     {
  759.         ClrSignal(SIG_HANDSHAKE);
  760.  
  761.         Wait(SIG_HANDSHAKE);
  762.     }
  763.  
  764.     Permit();
  765.  
  766.     if(!FileRequesterProcess)
  767.     {
  768.         cprint("Could not create file requester process\n");
  769.  
  770.         return(FALSE);
  771.     }
  772.  
  773.     if(!(TimePort = CreateMsgPort()))
  774.     {
  775.         cprint("Could not create timer port\n");
  776.  
  777.         return(FALSE);
  778.     }
  779.  
  780.     if(!(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest))))
  781.     {
  782.         cprint("Could not create timer request\n");
  783.  
  784.         return(FALSE);
  785.     }
  786.  
  787.     if(OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  788.     {
  789.         cprint("Could not open timer\n");
  790.  
  791.         return(FALSE);
  792.     }
  793.  
  794.     TimerBase = (struct Library *)TimeRequest -> tr_node . io_Device;
  795.  
  796.     if(!(Anchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath) + 512,MEMF_ANY | MEMF_CLEAR)))
  797.     {
  798.         cprint("Could not allocate pattern matching buffe\n");
  799.  
  800.         return(FALSE);
  801.     }
  802.  
  803.     Anchor -> ap_Strlen = 512;
  804.  
  805.     if(!(ReadPort = CreateMsgPort()))
  806.     {
  807.         cprint("Could not create serial read port\n");
  808.  
  809.         return(FALSE);
  810.     }
  811.  
  812.     if(!(WritePort = CreateMsgPort()))
  813.     {
  814.         cprint("Could not create serial write port\n");
  815.  
  816.         return(FALSE);
  817.     }
  818.  
  819.     Forbid();
  820.  
  821.     if(RendezvousSemaphore = (struct RendezvousSemaphore *)FindSemaphore(Device))
  822.     {
  823.         ObtainSemaphore(RendezvousSemaphore);
  824.  
  825.         if(!(RendezvousData = (*RendezvousSemaphore -> rs_Login)(ReadPort,WritePort,NULL)))
  826.         {
  827.             Permit();
  828.  
  829.             ReleaseSemaphore(RendezvousSemaphore);
  830.  
  831.             RendezvousSemaphore = NULL;
  832.  
  833.             cprint("Could not link to `term' port \"%s\"\n",Device);
  834.  
  835.             return(FALSE);
  836.         }
  837.     }
  838.  
  839.     Permit();
  840.  
  841.     if(!(ConsoleReadPort = CreateMsgPort()))
  842.     {
  843.         cprint("Could not create console read port\n");
  844.  
  845.         return(FALSE);
  846.     }
  847.  
  848.     if(!(ConsoleWritePort = CreateMsgPort()))
  849.     {
  850.         cprint("Could not create console write port\n");
  851.  
  852.         return(FALSE);
  853.     }
  854.  
  855.     if(!(ConsoleReadRequest = (struct IOStdReq *)AllocVec(sizeof(struct IOStdReq),MEMF_ANY | MEMF_PUBLIC | MEMF_CLEAR)))
  856.     {
  857.         cprint("Could not create console read request\n");
  858.  
  859.         return(FALSE);
  860.     }
  861.  
  862.     if(!RendezvousData)
  863.     {
  864.         if(!(ReadBuffer = CreateSerialBuffer(Device,Unit,BUFFER_SIZE,ReadPort)))
  865.             return(FALSE);
  866.     }
  867.     else
  868.     {
  869.         if(ReadBuffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + BUFFER_SIZE,MEMF_ANY | MEMF_PUBLIC))
  870.         {
  871.             ReadBuffer -> SerialBuffer    = ReadBuffer -> SerialIndex = (UBYTE *)(ReadBuffer + 1);
  872.             ReadBuffer -> SerialFilled    = 0;
  873.             ReadBuffer -> SerialTop        = ReadBuffer -> SerialBuffer + BUFFER_SIZE;
  874.             ReadBuffer -> SerialSize    = BUFFER_SIZE;
  875.             ReadBuffer -> IsClone        = TRUE;
  876.             ReadBuffer -> IsBusy        = FALSE;
  877.             ReadBuffer -> SerialRequest    = &RendezvousData -> rd_ReadRequest;
  878.         }
  879.         else
  880.         {
  881.             cprint("Could not create serial ReadBuffer\n");
  882.  
  883.             return(FALSE);
  884.         }
  885.     }
  886.  
  887.     if(!(ThisBuffer = CloneSerialBuffer(ReadBuffer,WritePort)))
  888.         return(FALSE);
  889.  
  890.     if(!(NextBuffer = CloneSerialBuffer(ReadBuffer,WritePort)))
  891.         return(FALSE);
  892.  
  893.     if(!(PublicScreen = LockPubScreen(NULL)))
  894.     {
  895.         cprint("Could not find default public screen\n");
  896.  
  897.         return(FALSE);
  898.     }
  899.  
  900.     if(RendezvousData)
  901.     {
  902.         if(!(Screen = RendezvousData -> rd_Screen))
  903.             Screen = PublicScreen;
  904.     }
  905.     else
  906.     {
  907.         if(!(Screen = OpenScreenTags(NULL,
  908.             SA_DisplayID,    GetVPModeID(&PublicScreen -> ViewPort),
  909.             SA_Overscan,    OSCAN_TEXT,
  910.             SA_Depth,    2,
  911.             SA_Title,    PRGNAME " " VERSION " " HC_OS " Amiga rev 5, ported by Olaf `Olsen' Barthel",
  912.             SA_Behind,    TRUE,
  913.             SA_SysFont,    1,
  914.             SA_Pens,    &Pens,
  915.             SA_Interleaved,    TRUE,
  916.         TAG_DONE)))
  917.         {
  918.             cprint("Could not open screen\n");
  919.  
  920.             return(FALSE);
  921.         }
  922.     }
  923.  
  924.     if(!(VisualInfo = GetVisualInfo(Screen,TAG_DONE)))
  925.     {
  926.         cprint("Could not obtain screen visual info\n");
  927.  
  928.         return(FALSE);
  929.     }
  930.  
  931.     if(!(Menu = CreateMenus(MenuTemplate,TAG_DONE)))
  932.     {
  933.         cprint("Could not create menus\n");
  934.  
  935.         return(FALSE);
  936.     }
  937.  
  938.     if(!LayoutMenus(Menu,VisualInfo,
  939.         GTMN_TextAttr,        Screen -> Font,
  940.         GTMN_NewLookMenus,    TRUE,
  941.     TAG_DONE))
  942.     {
  943.         cprint("Could not layout menus\n");
  944.  
  945.         return(FALSE);
  946.     }
  947.  
  948.     Top        = Screen -> BarHeight + 1;
  949.     BorderSize    = Screen -> WBorTop + Screen -> Font -> ta_YSize + 1 + Screen -> WBorBottom;
  950.     FontSize    = GfxBase -> DefaultFont -> tf_YSize;
  951.     TotalHeight    = Screen -> Height - Top;
  952.     Lines        = (TotalHeight - 3 - 4 * BorderSize) / FontSize;
  953.     ExtraLines    = Lines > MIN_LINES ? (Lines - MIN_LINES) / 3 : 0;
  954.     RemainingLines    = Lines > MIN_LINES + ExtraLines * 3 ? Lines - (MIN_LINES + ExtraLines * 3) : 0;
  955.  
  956.     if(Lines < MIN_LINES)
  957.     {
  958.         cprint("Screen size too small (need at least %d text lines, can get only %d)\n",MIN_LINES,Lines);
  959.  
  960.         return(FALSE);
  961.     }
  962.  
  963.     if(!OpenConsole(Screen,Top,BorderSize + (6 + ExtraLines) * FontSize,"Log",TRUE,&LogWindow,&LogRequest))
  964.     {
  965.         cprint("Could not open console window #1\n");
  966.  
  967.         return(FALSE);
  968.     }
  969.  
  970.     TotalHeight    -= LogWindow -> Height + 1;
  971.     Top        += LogWindow -> Height + 1;
  972.  
  973.     if(!OpenConsole(Screen,Top,BorderSize + 2 * FontSize,"File",FALSE,&FileWindow,&FileRequest))
  974.     {
  975.         cprint("Could not open console window #2\n");
  976.  
  977.         return(FALSE);
  978.     }
  979.  
  980.     TotalHeight    -= FileWindow -> Height + 1;
  981.     Top        += FileWindow -> Height + 1;
  982.  
  983.     if(!OpenConsole(Screen,Top,BorderSize + (8 + RemainingLines) * FontSize,"Remote",TRUE,&RemoteWindow,&RemoteRequest))
  984.     {
  985.         cprint("Could not open console window #3\n");
  986.  
  987.         return(FALSE);
  988.     }
  989.  
  990.     TotalHeight    -= RemoteWindow -> Height + 1;
  991.     Top        += RemoteWindow -> Height + 1;
  992.  
  993.     if(!OpenConsole(Screen,Top,TotalHeight,"Local (Press [Amiga+C] to start/end chat mode, [Esc] to abort Hydra session)",TRUE,&LocalWindow,&LocalRequest))
  994.     {
  995.         cprint("Could not open console window #4\n");
  996.  
  997.         return(FALSE);
  998.     }
  999.  
  1000.     SetMenuStrip(LocalWindow,Menu);
  1001.  
  1002.     if(!ModifyIDCMP(LocalWindow,IDCMP_MENUPICK))
  1003.     {
  1004.         cprint("Could not modify IDCMP flags\n");
  1005.  
  1006.         return(FALSE);
  1007.     }
  1008.  
  1009.     LocalWindow -> Flags &= ~WFLG_RMBTRAP;
  1010.  
  1011.     CopyMem(LocalRequest,ConsoleReadRequest,sizeof(struct IOStdReq));
  1012.  
  1013.     ConsoleReadRequest -> io_Message . mn_ReplyPort = ConsoleReadPort;
  1014.  
  1015.         /* Turn the cursors back on. */
  1016.  
  1017.     ConPrintf(LocalRequest,"\33[ p");
  1018.     ConPrintf(RemoteRequest,"\33[ p");
  1019.  
  1020.     ConsoleReadRequest -> io_Command    = CMD_READ;
  1021.     ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1022.     ConsoleReadRequest -> io_Length        = 1;
  1023.  
  1024.     ClrSignal(SIG_CONREAD);
  1025.     SendIO(ConsoleReadRequest);
  1026.  
  1027.     OldPtr = ThisProcess -> pr_WindowPtr;
  1028.  
  1029.     ThisProcess -> pr_WindowPtr = (APTR)LocalWindow;
  1030.  
  1031.     ScreenToFront(Screen);
  1032.  
  1033.     ActivateWindow(LocalWindow);
  1034.  
  1035.     UnlockPubScreen(NULL,PublicScreen);
  1036.  
  1037.     PublicScreen = NULL;
  1038.  
  1039.     return(TRUE);
  1040. }
  1041.  
  1042.     /* CloseAll():
  1043.      *
  1044.      *    Close all the resources.
  1045.      */
  1046.  
  1047. STATIC VOID
  1048. CloseAll(VOID)
  1049. {
  1050.     if(FileRequesterProcess)
  1051.     {
  1052.         Forbid();
  1053.  
  1054.         ClrSignal(SIG_HANDSHAKE);
  1055.  
  1056.         Signal(FileRequesterProcess,SIG_KILL);
  1057.  
  1058.         Wait(SIG_HANDSHAKE);
  1059.  
  1060.         Permit();
  1061.     }
  1062.  
  1063.     if(LocalWindow)
  1064.         ClearMenuStrip(LocalWindow);
  1065.  
  1066.     if(Menu)
  1067.         FreeMenus(Menu);
  1068.  
  1069.     if(VisualInfo)
  1070.         FreeVisualInfo(VisualInfo);
  1071.  
  1072.     if(AnchorUsed)
  1073.         MatchEnd(Anchor);
  1074.  
  1075.     if(Anchor)
  1076.         FreeVec(Anchor);
  1077.  
  1078.     if(ThisProcess)
  1079.         ThisProcess -> pr_WindowPtr = OldPtr;
  1080.  
  1081.     if(ConsoleReadRequest)
  1082.     {
  1083.         if(ConsoleReadRequest -> io_Device)
  1084.         {
  1085.             if(!CheckIO(ConsoleReadRequest))
  1086.                 AbortIO(ConsoleReadRequest);
  1087.  
  1088.             WaitIO(ConsoleReadRequest);
  1089.         }
  1090.  
  1091.         FreeVec(ConsoleReadRequest);
  1092.     }
  1093.  
  1094.     CloseConsole(&LocalWindow,&LocalRequest);
  1095.     CloseConsole(&RemoteWindow,&RemoteRequest);
  1096.     CloseConsole(&FileWindow,&FileRequest);
  1097.     CloseConsole(&LogWindow,&LogRequest);
  1098.  
  1099.     if(!RendezvousData && Screen)
  1100.         CloseScreen(Screen);
  1101.  
  1102.     if(PublicScreen)
  1103.         UnlockPubScreen(NULL,PublicScreen);
  1104.  
  1105.     DeleteSerialBuffer(NextBuffer);
  1106.     DeleteSerialBuffer(ThisBuffer);
  1107.  
  1108.     if(RendezvousData)
  1109.     {
  1110.         if(ReadBuffer -> IsBusy)
  1111.         {
  1112.             if(!CheckIO(ReadBuffer -> SerialRequest))
  1113.                 AbortIO(ReadBuffer -> SerialRequest);
  1114.  
  1115.             WaitIO(ReadBuffer -> SerialRequest);
  1116.         }
  1117.  
  1118.         FreeVec(ReadBuffer);
  1119.     }
  1120.     else
  1121.         DeleteSerialBuffer(ReadBuffer);
  1122.  
  1123.     if(ConsoleWritePort)
  1124.         DeleteMsgPort(ConsoleWritePort);
  1125.  
  1126.     if(ConsoleReadPort)
  1127.         DeleteMsgPort(ConsoleReadPort);
  1128.  
  1129.     if(WritePort)
  1130.         DeleteMsgPort(WritePort);
  1131.  
  1132.     if(ReadPort)
  1133.         DeleteMsgPort(ReadPort);
  1134.  
  1135.     if(TimeRequest)
  1136.     {
  1137.         if(TimeRequest -> tr_node . io_Device)
  1138.             CloseDevice(TimeRequest);
  1139.  
  1140.         DeleteIORequest(TimeRequest);
  1141.     }
  1142.  
  1143.     if(TimePort)
  1144.         DeleteMsgPort(TimePort);
  1145.  
  1146.     if(UtilityBase)
  1147.         CloseLibrary(UtilityBase);
  1148.  
  1149.     if(AslBase)
  1150.         CloseLibrary(AslBase);
  1151.  
  1152.     if(GadToolsBase)
  1153.         CloseLibrary(GadToolsBase);
  1154.  
  1155.     if(GfxBase)
  1156.         CloseLibrary(GfxBase);
  1157.  
  1158.     if(IntuitionBase)
  1159.         CloseLibrary(IntuitionBase);
  1160.  
  1161.     if(RendezvousData)
  1162.     {
  1163.         (*RendezvousSemaphore -> rs_Logoff)(RendezvousData);
  1164.  
  1165.         RendezvousData = NULL;
  1166.     }
  1167.  
  1168.     if(RendezvousSemaphore)
  1169.     {
  1170.         ReleaseSemaphore(RendezvousSemaphore);
  1171.  
  1172.         RendezvousSemaphore = NULL;
  1173.     }
  1174. }
  1175.  
  1176.     /* ConPutc():
  1177.      *
  1178.      *    Output a single character.
  1179.      */
  1180.  
  1181. VOID __stdargs
  1182. ConPutc(struct IOStdReq *Request,UBYTE Char)
  1183. {
  1184.     Request -> io_Command    = CMD_WRITE;
  1185.     Request -> io_Data    = &Char;
  1186.     Request -> io_Length    = 1;
  1187.  
  1188.     DoIO(Request);
  1189. }
  1190.  
  1191.     /* ConPuts():
  1192.      *
  1193.      *    Output a string.
  1194.      */
  1195.  
  1196. VOID
  1197. ConPuts(struct IOStdReq *Request,STRPTR String)
  1198. {
  1199.     Request -> io_Command    = CMD_WRITE;
  1200.     Request -> io_Data    = String;
  1201.     Request -> io_Length    = strlen(String);
  1202.  
  1203.     DoIO(Request);
  1204. }
  1205.  
  1206.     /* ConPrintf():
  1207.      *
  1208.      *    Formatted console output.
  1209.      */
  1210.  
  1211. VOID __stdargs
  1212. ConPrintf(struct IOStdReq *Request,STRPTR Format,...)
  1213. {
  1214.     STATIC UBYTE Buffer[512];
  1215.  
  1216.     va_list VarArgs;
  1217.  
  1218.     va_start(VarArgs,Format);
  1219.     vsprintf(Buffer,Format,VarArgs);
  1220.     va_end(VarArgs);
  1221.  
  1222.     Request -> io_Command    = CMD_WRITE;
  1223.     Request -> io_Data    = Buffer;
  1224.     Request -> io_Length    = strlen(Buffer);
  1225.  
  1226.     DoIO(Request);
  1227. }
  1228.  
  1229.     /* ConMove():
  1230.      *
  1231.      *    Move the cursor to a new position.
  1232.      */
  1233.  
  1234. VOID
  1235. ConMove(struct IOStdReq *Request,LONG x,LONG y)
  1236. {
  1237.     ConPrintf(Request,"\33[%ld;%ldH",y,x);
  1238. }
  1239.  
  1240.     /* ConClear():
  1241.      *
  1242.      *    Clear the console window.
  1243.      */
  1244.  
  1245. VOID
  1246. ConClear(struct IOStdReq *Request)
  1247. {
  1248.     struct ConUnit *ConUnit = (struct ConUnit *)Request -> io_Device;
  1249.     LONG x,y;
  1250.  
  1251.     x = ConUnit -> cu_XCCP;
  1252.     y = ConUnit -> cu_YCCP;
  1253.  
  1254.     ConPrintf(Request,"\f\33[%ld;%ldH",y,x);
  1255. }
  1256.  
  1257.     /* ConGetKey():
  1258.      *
  1259.      *    Read a character from a console window.
  1260.      */
  1261.  
  1262. int
  1263. ConGetKey()
  1264. {
  1265.     if(ConsoleReady)
  1266.     {
  1267.         int Result = ConsoleChar;
  1268.  
  1269.         ConsoleReady = FALSE;
  1270.  
  1271.         ConsoleReadRequest -> io_Command    = CMD_READ;
  1272.         ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1273.         ConsoleReadRequest -> io_Length        = 1;
  1274.  
  1275.         ClrSignal(SIG_CONREAD);
  1276.         SendIO(ConsoleReadRequest);
  1277.  
  1278.         return(Result);
  1279.     }
  1280.     else
  1281.     {
  1282.         int Result = 0;
  1283.  
  1284.         if(WindowReady)
  1285.         {
  1286.             struct IntuiMessage *IntuiMessage;
  1287.             ULONG MsgClass;
  1288.             UWORD MsgCode;
  1289.  
  1290.             while(IntuiMessage = (struct IntuiMessage *)GetMsg(LocalWindow -> UserPort))
  1291.             {
  1292.                 MsgClass    = IntuiMessage -> Class;
  1293.                 MsgCode        = IntuiMessage -> Code;
  1294.  
  1295.                 ReplyMsg(IntuiMessage);
  1296.  
  1297.                 if(MsgClass == IDCMP_MENUPICK)
  1298.                 {
  1299.                     struct MenuItem *Item;
  1300.  
  1301.                     while(MsgCode != MENUNULL)
  1302.                     {
  1303.                         if(Item = ItemAddress(Menu,MsgCode))
  1304.                         {
  1305.                             if(MENU_USERDATA(Item))
  1306.                             {
  1307.                                 if(!Result)
  1308.                                     Result = (int)MENU_USERDATA(Item);
  1309.                             }
  1310.  
  1311.                             MsgCode = Item -> NextSelect;
  1312.                         }
  1313.                         else
  1314.                             break;
  1315.                     }
  1316.                 }
  1317.             }
  1318.  
  1319.             WindowReady = FALSE;
  1320.         }
  1321.  
  1322.         return(Result);
  1323.     }
  1324. }
  1325.  
  1326.     /* ConScanKey():
  1327.      *
  1328.      *    Check for a keyboard event.
  1329.      */
  1330.  
  1331. int
  1332. ConScanKey()
  1333. {
  1334.     if(ConsoleReady || WindowReady)
  1335.         return(1);
  1336.     else
  1337.     {
  1338.         int Result = 0;
  1339.  
  1340.         if(CheckSignal(SIG_WINDOW))
  1341.         {
  1342.             WindowReady = TRUE;
  1343.  
  1344.             Result = 1;
  1345.         }
  1346.  
  1347.         if(CheckIO(ConsoleReadRequest))
  1348.         {
  1349.             if(!WaitIO(ConsoleReadRequest))
  1350.             {
  1351.                 ConsoleReady = TRUE;
  1352.  
  1353.                 return(1);
  1354.             }
  1355.             else
  1356.             {
  1357.                 ConsoleReadRequest -> io_Command    = CMD_READ;
  1358.                 ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1359.                 ConsoleReadRequest -> io_Length        = 1;
  1360.  
  1361.                 ClrSignal(SIG_CONREAD);
  1362.                 SendIO(ConsoleReadRequest);
  1363.             }
  1364.         }
  1365.  
  1366.         return(Result);
  1367.     }
  1368.  
  1369.     return(0);
  1370. }
  1371.  
  1372.     /* dtr_out(byte flag):
  1373.      *
  1374.      *    If flag == 0 -> drop DTR signal, else set it.
  1375.      */
  1376.  
  1377. VOID
  1378. dtr_out(byte flag)
  1379. {
  1380.     if(!flag && !RendezvousData)
  1381.     {
  1382.         if(ThisBuffer -> IsBusy)
  1383.         {
  1384.             WaitIO(ThisBuffer -> SerialRequest);
  1385.  
  1386.             ThisBuffer -> IsBusy        = FALSE;
  1387.             ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1388.         }
  1389.  
  1390.         if(ReadBuffer -> IsBusy)
  1391.         {
  1392.             if(!CheckIO(ReadBuffer -> SerialRequest))
  1393.                 AbortIO(ReadBuffer -> SerialRequest);
  1394.  
  1395.             WaitIO(ReadBuffer -> SerialRequest);
  1396.  
  1397.             ReadBuffer -> IsBusy        = FALSE;
  1398.             ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1399.             ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1400.  
  1401.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1402.  
  1403.             DoIO(ReadBuffer -> SerialRequest);
  1404.  
  1405.             if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1406.             {
  1407.                 LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1408.  
  1409.                 if(Size > 0)
  1410.                 {
  1411.                     if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1412.                         Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1413.  
  1414.                     ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1415.                     ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1416.                     ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1417.  
  1418.                     DoIO(ReadBuffer -> SerialRequest);
  1419.  
  1420.                     ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1421.                 }
  1422.             }
  1423.         }
  1424.  
  1425.         CloseDevice(ReadBuffer -> SerialRequest);
  1426.  
  1427.         TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1428.         TimeRequest -> tr_time . tv_secs    = 1;
  1429.         TimeRequest -> tr_time . tv_micro    = 0;
  1430.  
  1431.         DoIO(TimeRequest);
  1432.  
  1433.         if(OpenDevice(device,port,ReadBuffer -> SerialRequest,NULL))
  1434.         {
  1435.             CloseAll();
  1436.  
  1437.             exit(10);
  1438.         }
  1439.         else
  1440.         {
  1441.             ReadBuffer -> SerialRequest -> io_Baud        = ThisBuffer -> SerialRequest -> io_Baud;
  1442.             ReadBuffer -> SerialRequest -> io_ReadLen    = ThisBuffer -> SerialRequest -> io_ReadLen;
  1443.             ReadBuffer -> SerialRequest -> io_WriteLen    = ThisBuffer -> SerialRequest -> io_WriteLen;
  1444.             ReadBuffer -> SerialRequest -> io_SerFlags    = ThisBuffer -> SerialRequest -> io_SerFlags;
  1445.  
  1446.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1447.  
  1448.             DoIO(ReadBuffer -> SerialRequest);
  1449.  
  1450.             CopyMem(ReadBuffer -> SerialRequest,ThisBuffer -> SerialRequest,sizeof(struct IOExtSer));
  1451.  
  1452.             ThisBuffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = WritePort;
  1453.  
  1454.             CopyMem(ReadBuffer -> SerialRequest,NextBuffer -> SerialRequest,sizeof(struct IOExtSer));
  1455.  
  1456.             NextBuffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = WritePort;
  1457.         }
  1458.     }
  1459. }
  1460.  
  1461.     /* com_flow(byte flags):
  1462.      *
  1463.      *    The bit mask `flags' determines the style(s) of
  1464.      *    handshaking:
  1465.      *
  1466.      *    if (flags & 9) -> enable xON/xOFF software handshaking,
  1467.      *    if (flags & 2) -> enable RTS/CTS hardware handshaking
  1468.      */
  1469.  
  1470. VOID
  1471. com_flow(byte flags)
  1472. {
  1473.     if(ThisBuffer -> IsBusy)
  1474.     {
  1475.         WaitIO(ThisBuffer -> SerialRequest);
  1476.  
  1477.         ThisBuffer -> IsBusy        = FALSE;
  1478.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1479.     }
  1480.  
  1481.     if(ReadBuffer -> IsBusy)
  1482.     {
  1483.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1484.             AbortIO(ReadBuffer -> SerialRequest);
  1485.  
  1486.         WaitIO(ReadBuffer -> SerialRequest);
  1487.  
  1488.         ReadBuffer -> IsBusy        = FALSE;
  1489.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1490.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1491.  
  1492.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1493.  
  1494.         DoIO(ReadBuffer -> SerialRequest);
  1495.  
  1496.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1497.         {
  1498.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1499.  
  1500.             if(Size > 0)
  1501.             {
  1502.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1503.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1504.  
  1505.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1506.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1507.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1508.  
  1509.                 DoIO(ReadBuffer -> SerialRequest);
  1510.  
  1511.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1512.             }
  1513.         }
  1514.     }
  1515.  
  1516.     if(flags & 2)
  1517.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_7WIRE;
  1518.     else
  1519.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_7WIRE;
  1520.  
  1521.     if(flags & 9)
  1522.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_XDISABLED;
  1523.     else
  1524.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_XDISABLED;
  1525.  
  1526.     ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1527.  
  1528.     DoIO(ReadBuffer -> SerialRequest);
  1529.  
  1530.     ThisBuffer -> SerialRequest -> io_SerFlags = ReadBuffer -> SerialRequest -> io_SerFlags;
  1531.     NextBuffer -> SerialRequest -> io_SerFlags = ReadBuffer -> SerialRequest -> io_SerFlags;
  1532. }
  1533.  
  1534.     /* com_setspeed(word speed):
  1535.      *
  1536.      *    Set the transfer speed (in bits/second).
  1537.      */
  1538.  
  1539. VOID
  1540. com_setspeed(word speed)
  1541. {
  1542.     if(ThisBuffer -> IsBusy)
  1543.     {
  1544.         WaitIO(ThisBuffer -> SerialRequest);
  1545.  
  1546.         ThisBuffer -> IsBusy        = FALSE;
  1547.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1548.     }
  1549.  
  1550.     if(ReadBuffer -> IsBusy)
  1551.     {
  1552.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1553.             AbortIO(ReadBuffer -> SerialRequest);
  1554.  
  1555.         WaitIO(ReadBuffer -> SerialRequest);
  1556.  
  1557.         ReadBuffer -> IsBusy        = FALSE;
  1558.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1559.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1560.  
  1561.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1562.  
  1563.         DoIO(ReadBuffer -> SerialRequest);
  1564.  
  1565.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1566.         {
  1567.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1568.  
  1569.             if(Size > 0)
  1570.             {
  1571.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1572.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1573.  
  1574.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1575.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1576.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1577.  
  1578.                 DoIO(ReadBuffer -> SerialRequest);
  1579.  
  1580.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1581.             }
  1582.         }
  1583.     }
  1584.  
  1585.     ReadBuffer -> SerialRequest -> io_Baud = speed;
  1586.  
  1587.     if(parity)
  1588.     {
  1589.         ReadBuffer -> SerialRequest -> io_ReadLen = ReadBuffer -> SerialRequest -> io_WriteLen = 7;
  1590.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_PARTY_ON;
  1591.     }
  1592.     else
  1593.     {
  1594.         ReadBuffer -> SerialRequest -> io_ReadLen = ReadBuffer -> SerialRequest -> io_WriteLen = 8;
  1595.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_PARTY_ON;
  1596.     }
  1597.  
  1598.     ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1599.  
  1600.     DoIO(ReadBuffer -> SerialRequest);
  1601.  
  1602.     ThisBuffer -> SerialRequest -> io_Baud        = ReadBuffer -> SerialRequest -> io_Baud;
  1603.     ThisBuffer -> SerialRequest -> io_ReadLen    = ReadBuffer -> SerialRequest -> io_ReadLen;
  1604.     ThisBuffer -> SerialRequest -> io_WriteLen    = ReadBuffer -> SerialRequest -> io_WriteLen;
  1605.     ThisBuffer -> SerialRequest -> io_SerFlags    = ReadBuffer -> SerialRequest -> io_SerFlags;
  1606.  
  1607.     NextBuffer -> SerialRequest -> io_Baud        = ReadBuffer -> SerialRequest -> io_Baud;
  1608.     NextBuffer -> SerialRequest -> io_ReadLen    = ReadBuffer -> SerialRequest -> io_ReadLen;
  1609.     NextBuffer -> SerialRequest -> io_WriteLen    = ReadBuffer -> SerialRequest -> io_WriteLen;
  1610.     NextBuffer -> SerialRequest -> io_SerFlags    = ReadBuffer -> SerialRequest -> io_SerFlags;
  1611. }
  1612.  
  1613.     /* com_putblock(byte *s,word len):
  1614.      *
  1615.      *    Send a data block asynchronously.
  1616.      */
  1617.  
  1618. VOID
  1619. com_putblock(byte *s,word len)
  1620. {
  1621.     struct SerialBuffer *Swap = ThisBuffer;
  1622.  
  1623.     if(ThisBuffer -> IsBusy)
  1624.         WaitIO(ThisBuffer -> SerialRequest);
  1625.     else
  1626.     {
  1627.         if(ThisBuffer -> SerialIndex > ThisBuffer -> SerialBuffer)
  1628.         {
  1629.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1630.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1631.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1632.  
  1633.             DoIO(ThisBuffer -> SerialRequest);
  1634.         }
  1635.     }
  1636.  
  1637.     ThisBuffer -> IsBusy        = FALSE;
  1638.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1639.  
  1640.     ThisBuffer = NextBuffer;
  1641.     NextBuffer = Swap;
  1642.  
  1643.     if(ThisBuffer -> SerialIndex > ThisBuffer -> SerialBuffer)
  1644.     {
  1645.         ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1646.         ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1647.         ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1648.  
  1649.         DoIO(ThisBuffer -> SerialRequest);
  1650.     }
  1651.  
  1652.     ThisBuffer -> IsBusy        = FALSE;
  1653.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1654.  
  1655.     while(len > 2 * ThisBuffer -> SerialSize)
  1656.     {
  1657.         ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1658.         ThisBuffer -> SerialRequest -> IOSer . io_Data        = s;
  1659.         ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialSize;
  1660.  
  1661.         s    += ThisBuffer -> SerialSize;
  1662.         len    -= ThisBuffer -> SerialSize;
  1663.  
  1664.         DoIO(ThisBuffer -> SerialRequest);
  1665.     }
  1666.  
  1667.     CopyMem(s,ThisBuffer -> SerialBuffer,MIN(len,ThisBuffer -> SerialSize));
  1668.  
  1669.     ThisBuffer -> IsBusy                    = TRUE;
  1670.     ThisBuffer -> SerialIndex                = ThisBuffer -> SerialBuffer + MIN(len,ThisBuffer -> SerialSize);
  1671.     ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1672.     ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1673.     ThisBuffer -> SerialRequest -> IOSer . io_Length    = MIN(len,ThisBuffer -> SerialSize);
  1674.  
  1675.     len    -= ThisBuffer -> SerialRequest -> IOSer . io_Length;
  1676.     s    += ThisBuffer -> SerialRequest -> IOSer . io_Length;
  1677.  
  1678.     ClrSignal(SIG_SERWRITE);
  1679.     SendIO(ThisBuffer -> SerialRequest);
  1680.  
  1681.     if(len > 0)
  1682.     {
  1683.         CopyMem(s,NextBuffer -> SerialBuffer,len);
  1684.  
  1685.         NextBuffer -> SerialIndex = NextBuffer -> SerialBuffer + len;
  1686.     }
  1687. }
  1688.  
  1689.     /* breakfunc():
  1690.      *
  1691.      *    Cleanup routine for SAS/C.
  1692.      */
  1693.  
  1694. static int
  1695. breakfunc(void)
  1696. {
  1697.     CloseAll();
  1698.  
  1699.     return(1);
  1700. }
  1701.  
  1702.     /* sys_init(VOID):
  1703.      *
  1704.      *    Initialize this driver implementation.
  1705.      */
  1706.  
  1707. VOID
  1708. sys_init(VOID)
  1709. {
  1710.     if(!OpenAll(device,port))
  1711.     {
  1712.         CloseAll();
  1713.  
  1714.         endprog(2);
  1715.     }
  1716.  
  1717.     onbreak(breakfunc);
  1718. }
  1719.  
  1720.     /* sys_reset(VOID):
  1721.      *
  1722.      *    Perform cleanup for this driver implementation.
  1723.      */
  1724.  
  1725. VOID
  1726. sys_reset(VOID)
  1727. {
  1728.     CloseAll();
  1729. }
  1730.  
  1731.     /* sys_idle(VOID):
  1732.      *
  1733.      *    This routine gets called when the system is idle.
  1734.      *    That's a nice one. We are supposed to call the
  1735.      *    system scheduler, etc.
  1736.      */
  1737.  
  1738. VOID
  1739. sys_idle(VOID)
  1740. {
  1741.     ULONG Signals;
  1742.  
  1743.     if(ReadBuffer -> SerialFilled <= 0 && !ReadBuffer -> IsBusy)
  1744.     {
  1745.         ReadBuffer -> IsBusy                    = TRUE;
  1746.         ReadBuffer -> SerialIndex                = ReadBuffer -> SerialBuffer;
  1747.         ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1748.         ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  1749.         ReadBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  1750.  
  1751.         ClrSignal(SIG_SERREAD);
  1752.         SendIO(ReadBuffer -> SerialRequest);
  1753.     }
  1754.  
  1755.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1756.     TimeRequest -> tr_time . tv_secs    = 1;
  1757.     TimeRequest -> tr_time . tv_micro    = 0;
  1758.  
  1759.     ClrSignal(SIG_TIMER);
  1760.     SendIO(TimeRequest);
  1761.  
  1762.     Signals = Wait(SIG_SERREAD | SIG_SERWRITE | SIG_CONREAD | SIG_WINDOW | SIG_TIMER);
  1763.  
  1764.     if(!(Signals & SIG_TIMER))
  1765.     {
  1766.         if(!CheckIO(TimeRequest))
  1767.             AbortIO(TimeRequest);
  1768.     }
  1769.  
  1770.     WaitIO(TimeRequest);
  1771.  
  1772.     if(Signals & SIG_SERREAD)
  1773.     {
  1774.         WaitIO(ReadBuffer -> SerialRequest);
  1775.  
  1776.         ReadBuffer -> IsBusy        = FALSE;
  1777.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1778.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1779.  
  1780.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1781.  
  1782.         DoIO(ReadBuffer -> SerialRequest);
  1783.  
  1784.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1785.         {
  1786.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1787.  
  1788.             if(Size > 0)
  1789.             {
  1790.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1791.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1792.  
  1793.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1794.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1795.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1796.  
  1797.                 DoIO(ReadBuffer -> SerialRequest);
  1798.  
  1799.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1800.             }
  1801.         }
  1802.     }
  1803.  
  1804.     if(Signals & SIG_SERWRITE)
  1805.     {
  1806.         struct SerialBuffer *Swap = ThisBuffer;
  1807.  
  1808.         WaitIO(ThisBuffer -> SerialRequest);
  1809.  
  1810.         ThisBuffer -> IsBusy        = FALSE;
  1811.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1812.  
  1813.         ThisBuffer = NextBuffer;
  1814.         NextBuffer = Swap;
  1815.     }
  1816.  
  1817.     if(Signals & SIG_CONREAD)
  1818.     {
  1819.         WaitIO(ConsoleReadRequest);
  1820.  
  1821.         ConsoleReady = TRUE;
  1822.     }
  1823.  
  1824.     if(Signals & SIG_WINDOW)
  1825.         WindowReady = TRUE;
  1826. }
  1827.  
  1828.     /* com_outfull(VOID):
  1829.      *
  1830.      *    Return number of bytes still to be transferred.
  1831.      */
  1832.  
  1833. int
  1834. com_outfull(VOID)
  1835. {
  1836.     return(ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer + NextBuffer -> SerialIndex - NextBuffer -> SerialBuffer);
  1837. }
  1838.  
  1839.     /* carrier(VOID):
  1840.      *
  1841.      *    Return current carrier status.
  1842.      */
  1843.  
  1844. int
  1845. carrier(VOID)
  1846. {
  1847.     if(nocarrier)
  1848.         return(1);
  1849.     else
  1850.     {
  1851.         if(!ThisBuffer -> IsBusy)
  1852.         {
  1853.             ThisBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1854.  
  1855.             DoIO(ThisBuffer -> SerialRequest);
  1856.  
  1857.             if(ThisBuffer -> SerialRequest -> io_Status & CIAF_COMCD)
  1858.                 return(0);
  1859.             else
  1860.                 return(1);
  1861.         }
  1862.         else
  1863.         {
  1864.             NextBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1865.  
  1866.             DoIO(NextBuffer -> SerialRequest);
  1867.  
  1868.             if(NextBuffer -> SerialRequest -> io_Status & CIAF_COMCD)
  1869.                 return(0);
  1870.             else
  1871.                 return(1);
  1872.         }
  1873.     }
  1874. }
  1875.  
  1876.     /* com_flush(VOID):
  1877.      *
  1878.      *    Make sure all pending data gets written.
  1879.      */
  1880.  
  1881. VOID
  1882. com_flush(VOID)
  1883. {
  1884.     if(ThisBuffer -> IsBusy)
  1885.     {
  1886.         WaitIO(ThisBuffer -> SerialRequest);
  1887.  
  1888.         ThisBuffer -> IsBusy        = FALSE;
  1889.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1890.     }
  1891.  
  1892.     if(NextBuffer -> SerialIndex > NextBuffer -> SerialBuffer)
  1893.     {
  1894.         NextBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1895.         NextBuffer -> SerialRequest -> IOSer . io_Data        = NextBuffer -> SerialBuffer;
  1896.         NextBuffer -> SerialRequest -> IOSer . io_Length    = NextBuffer -> SerialIndex - NextBuffer -> SerialBuffer;
  1897.  
  1898.         DoIO(NextBuffer -> SerialRequest);
  1899.  
  1900.         NextBuffer -> SerialIndex = NextBuffer -> SerialBuffer;
  1901.     }
  1902. }
  1903.  
  1904.     /* com_putbyte(byte c):
  1905.      *
  1906.      *    Transmit a single byte, queueing it if necessary.
  1907.      */
  1908.  
  1909. VOID
  1910. com_putbyte(byte c)
  1911. {
  1912.     if(ThisBuffer -> IsBusy)
  1913.     {
  1914.         if(NextBuffer -> SerialIndex + 1 >= NextBuffer -> SerialTop)
  1915.         {
  1916.             struct SerialBuffer *Swap = ThisBuffer;
  1917.  
  1918.             WaitIO(ThisBuffer -> SerialRequest);
  1919.  
  1920.             ThisBuffer -> IsBusy        = FALSE;
  1921.             ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1922.  
  1923.             ThisBuffer = NextBuffer;
  1924.             NextBuffer = Swap;
  1925.  
  1926.             ThisBuffer -> IsBusy                    = TRUE;
  1927.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1928.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1929.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1930.  
  1931.             ClrSignal(SIG_SERWRITE);
  1932.             SendIO(ThisBuffer -> SerialRequest);
  1933.         }
  1934.  
  1935.         *NextBuffer -> SerialIndex++ = c;
  1936.     }
  1937.     else
  1938.     {
  1939.         if(ThisBuffer -> SerialIndex + 1 < ThisBuffer -> SerialTop)
  1940.         {
  1941.             *ThisBuffer -> SerialIndex++ = c;
  1942.  
  1943.             ThisBuffer -> IsBusy                    = TRUE;
  1944.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1945.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1946.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  1947.  
  1948.             ClrSignal(SIG_SERWRITE);
  1949.             SendIO(ThisBuffer -> SerialRequest);
  1950.         }
  1951.         else
  1952.         {
  1953.             ThisBuffer -> IsBusy                    = TRUE;
  1954.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1955.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1956.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1957.  
  1958.             ClrSignal(SIG_SERWRITE);
  1959.             SendIO(ThisBuffer -> SerialRequest);
  1960.  
  1961.             *NextBuffer -> SerialIndex++ = c;
  1962.         }
  1963.     }
  1964. }
  1965.  
  1966.     /* com_purge(VOID):
  1967.      *
  1968.      *    Clear the read/write buffers.
  1969.      */
  1970.  
  1971. VOID
  1972. com_purge(VOID)
  1973. {
  1974.     if(ThisBuffer -> IsBusy)
  1975.     {
  1976.         if(!CheckIO(ThisBuffer -> SerialRequest))
  1977.             AbortIO(ThisBuffer -> SerialRequest);
  1978.  
  1979.         WaitIO(ThisBuffer -> SerialRequest);
  1980.     }
  1981.  
  1982.     ThisBuffer -> IsBusy        = FALSE;
  1983.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1984.  
  1985.     NextBuffer -> IsBusy        = FALSE;
  1986.     NextBuffer -> SerialIndex    = NextBuffer -> SerialBuffer;
  1987.  
  1988.     if(ReadBuffer -> IsBusy)
  1989.     {
  1990.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1991.             AbortIO(ReadBuffer -> SerialRequest);
  1992.  
  1993.         WaitIO(ReadBuffer -> SerialRequest);
  1994.     }
  1995.  
  1996.     ReadBuffer -> IsBusy        = FALSE;
  1997.     ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1998.     ReadBuffer -> SerialFilled    = 0;
  1999.  
  2000.     ThisBuffer -> SerialRequest -> IOSer . io_Command = CMD_CLEAR;
  2001.     DoIO(ThisBuffer -> SerialRequest);
  2002. }
  2003.  
  2004.     /* com_dump(VOID):
  2005.      *
  2006.      *    Wait for asynchronous write request to terminate.
  2007.      */
  2008.  
  2009. VOID
  2010. com_dump(VOID)
  2011. {
  2012.     com_flush();
  2013. }
  2014.  
  2015.     /* com_getbyte(VOID):
  2016.      *
  2017.      *    Read a single byte from the serial line. If not available,
  2018.      *    return EOF.
  2019.      */
  2020.  
  2021. int
  2022. com_getbyte(VOID)
  2023. {
  2024.     int Result;
  2025.  
  2026.     if(ReadBuffer -> SerialFilled <= 0)
  2027.     {
  2028.         if(ReadBuffer -> IsBusy)
  2029.         {
  2030.             if(!CheckIO(ReadBuffer -> SerialRequest))
  2031.                 return(EOF);
  2032.             else
  2033.                 WaitIO(ReadBuffer -> SerialRequest);
  2034.  
  2035.             ReadBuffer -> IsBusy        = FALSE;
  2036.             ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2037.             ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  2038.  
  2039.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  2040.  
  2041.             DoIO(ReadBuffer -> SerialRequest);
  2042.  
  2043.             if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2044.             {
  2045.                 LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  2046.  
  2047.                 if(Size > 0)
  2048.                 {
  2049.                     if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2050.                         Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2051.  
  2052.                     ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2053.                     ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  2054.                     ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  2055.  
  2056.                     DoIO(ReadBuffer -> SerialRequest);
  2057.  
  2058.                     ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2059.                 }
  2060.             }
  2061.         }
  2062.         else
  2063.         {
  2064.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  2065.  
  2066.             DoIO(ReadBuffer -> SerialRequest);
  2067.  
  2068.             if(!ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2069.                 return(EOF);
  2070.             else
  2071.             {
  2072.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2073.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  2074.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = MIN(ReadBuffer -> SerialRequest -> IOSer . io_Actual,ReadBuffer -> SerialSize);
  2075.  
  2076.                 DoIO(ReadBuffer -> SerialRequest);
  2077.  
  2078.                 if(!ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2079.                     return(EOF);
  2080.                 else
  2081.                 {
  2082.                     ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2083.                     ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  2084.                 }
  2085.             }
  2086.         }
  2087.     }
  2088.  
  2089.     Result = *ReadBuffer -> SerialIndex++;
  2090.  
  2091.     ReadBuffer -> SerialFilled--;
  2092.  
  2093.     if(ReadBuffer -> SerialFilled <= 0)
  2094.     {
  2095.         ReadBuffer -> IsBusy                    = TRUE;
  2096.         ReadBuffer -> SerialIndex                = ReadBuffer -> SerialBuffer;
  2097.  
  2098.         ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2099.         ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  2100.         ReadBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  2101.  
  2102.         ClrSignal(SIG_SERREAD);
  2103.         SendIO(ReadBuffer -> SerialRequest);
  2104.     }
  2105.  
  2106.     return(Result);
  2107. }
  2108.  
  2109.     /* setstamp(STRPTR Name,LONG Time):
  2110.      *
  2111.      *    Set time/date of a file.
  2112.      */
  2113.  
  2114. VOID
  2115. setstamp(char *Name,long Time)
  2116. {
  2117.     struct DateStamp    Date;
  2118.     ULONG            Seconds;
  2119.  
  2120.         /* Translate it into an Amiga date. */
  2121.  
  2122.     if(Time > GMT_Offset)
  2123.         Seconds = Time - GMT_Offset;
  2124.     else
  2125.         Seconds = 0;
  2126.  
  2127.     Date . ds_Days        = Seconds / (24 * 60 * 60);
  2128.     Date . ds_Minute    = (Seconds % (24 * 60 * 60)) / 60;
  2129.     Date . ds_Tick        = (Seconds % 60) * TICKS_PER_SECOND;
  2130.  
  2131.     SetFileDate(Name,&Date);
  2132. }
  2133.  
  2134.     /* freespace(STRPTR DrivePath):
  2135.      *
  2136.      *    Get free disk space for specified drive.
  2137.      */
  2138.  
  2139. long
  2140. freespace(char *DrivePath)
  2141. {
  2142.     struct DevProc    *DevProc = GetDeviceProc(DrivePath,NULL);
  2143.     struct DosList    *DosList;
  2144.     BOOL         GoodDevice = FALSE;
  2145.     LONG         Size = (LONG)((ULONG)~0 >> 2);
  2146.  
  2147.     if(!DrivePath)
  2148.         DrivePath = "";
  2149.  
  2150.     if(DosList = LockDosList(LDF_DEVICES | LDF_READ))
  2151.     {
  2152.         while(DosList = NextDosEntry(DosList,LDF_DEVICES))
  2153.         {
  2154.             if(DosList -> dol_Task == DevProc -> dvp_Port)
  2155.             {
  2156.                 struct FileSysStartupMsg *FSSM = (struct FileSysStartupMsg *)BADDR(DosList -> dol_misc . dol_handler . dol_Startup);
  2157.  
  2158.                 if(TypeOfMem(FSSM))
  2159.                 {
  2160.                     struct DosEnvec *DosEnvec = (struct DosEnvec *)BADDR(FSSM -> fssm_Environ);
  2161.                     STRPTR Name = (STRPTR)BADDR(FSSM -> fssm_Device);
  2162.  
  2163.                     if(TypeOfMem(DosEnvec) && TypeOfMem(Name))
  2164.                     {
  2165.                         if(Name[0] > 0 && !Name[(WORD)Name[0] + 1])
  2166.                         {
  2167.                             struct IOStdReq __aligned IORequest;
  2168.  
  2169.                             if(!OpenDevice(Name + 1,FSSM -> fssm_Unit,&IORequest,FSSM -> fssm_Unit))
  2170.                             {
  2171.                                 CloseDevice(&IORequest);
  2172.  
  2173.                                 if(DosEnvec -> de_TableSize > 0 && DosEnvec -> de_LowCyl <= DosEnvec -> de_HighCyl)
  2174.                                     GoodDevice = TRUE;
  2175.                             }
  2176.                         }
  2177.                     }
  2178.                 }
  2179.             }
  2180.         }
  2181.  
  2182.         UnLockDosList(LDF_DEVICES | LDF_READ);
  2183.     }
  2184.  
  2185.     FreeDeviceProc(DevProc);
  2186.  
  2187.     if(GoodDevice)
  2188.     {
  2189.         struct InfoData *InfoData;
  2190.  
  2191.         if(InfoData = (struct InfoData *)AllocVec(sizeof(struct InfoData),MEMF_ANY | MEMF_PUBLIC))
  2192.         {
  2193.             UBYTE NewName[256],*Index;
  2194.             BPTR FileLock;
  2195.  
  2196.             memcpy(NewName,DrivePath,255);
  2197.  
  2198.             NewName[255] = 0;
  2199.  
  2200.             Index = PathPart(NewName);
  2201.  
  2202.             *Index = 0;
  2203.  
  2204.             FileLock = Lock(NewName,ACCESS_READ);
  2205.  
  2206.             if(FileLock)
  2207.             {
  2208.                 if(Info(FileLock,InfoData))
  2209.                     Size = InfoData -> id_BytesPerBlock * (InfoData -> id_NumBlocks - InfoData -> id_NumBlocksUsed);
  2210.  
  2211.                 UnLock(FileLock);
  2212.             }
  2213.  
  2214.             FreeVec(InfoData);
  2215.         }
  2216.     }
  2217.  
  2218.     return(Size);
  2219. }
  2220.  
  2221.     /* ffirst(char *FileSpec):
  2222.      *
  2223.      *    Return name of first file matching the given specs.
  2224.      */
  2225.  
  2226. char *
  2227. ffirst(char *filespec)
  2228. {
  2229.     AnchorUsed = TRUE;
  2230.  
  2231.     if(MatchFirst(filespec,Anchor))
  2232.         return(NULL);
  2233.     else
  2234.         return((char *)Anchor -> ap_Buf);
  2235. }
  2236.  
  2237.     /* fnext(VOID):
  2238.      *
  2239.      *    Return name of next file matching the given specs.
  2240.      */
  2241.  
  2242. char *
  2243. fnext(VOID)
  2244. {
  2245.     AnchorUsed = TRUE;
  2246.  
  2247.     if(MatchNext(Anchor))
  2248.         return(NULL);
  2249.     else
  2250.         return((char *)Anchor -> ap_Buf);
  2251. }
  2252.  
  2253.     /* time(time_t *timeptr):
  2254.      *
  2255.      *    Get the current time.
  2256.      */
  2257.  
  2258. time_t
  2259. time(time_t *timeptr)
  2260. {
  2261.     struct timeval    Now;
  2262.     time_t        CurrentTime;
  2263.  
  2264.         /* If the timer is already available,
  2265.          * just read the time. Otherwise, open what
  2266.          * we need to tell the time.
  2267.          */
  2268.  
  2269.     if(TimerBase)
  2270.         GetSysTime(&Now);
  2271.     else
  2272.         UpdateTime(&Now);
  2273.  
  2274.         /* Determine the current time, taking the time
  2275.          * zone into account.
  2276.          */
  2277.  
  2278.     CurrentTime = (time_t)(Now . tv_secs + GMT_Offset);
  2279.  
  2280.     if(timeptr)
  2281.         *timeptr = CurrentTime;
  2282.  
  2283.     return(CurrentTime);
  2284. }
  2285.  
  2286.     /* localtime(const time_t *t):
  2287.      *
  2288.      *    Convert UTC into local time.
  2289.      */
  2290.  
  2291. struct tm *
  2292. localtime(const time_t *t)
  2293. {
  2294.     STATIC struct tm Time;
  2295.  
  2296.     ULONG            Seconds,
  2297.                 Delta;
  2298.     struct ClockData    ClockData;
  2299.     BOOL            CloseIt = FALSE;
  2300.  
  2301.         /* We need utility.library for the date conversion. */
  2302.  
  2303.     if(!UtilityBase)
  2304.     {
  2305.         if(UtilityBase = OpenLibrary("utility.library",37))
  2306.             CloseIt = TRUE;
  2307.     }
  2308.  
  2309.         /* Any luck? */
  2310.  
  2311.     if(!UtilityBase)
  2312.     {
  2313.         memset(&Time,0,sizeof(struct tm));
  2314.  
  2315.         return(&Time);
  2316.     }
  2317.  
  2318.         /* Update the time data. */
  2319.  
  2320.     if(!TimerBase)
  2321.         UpdateTime(NULL);
  2322.  
  2323.         /* Add the offset. */
  2324.  
  2325.     if(*t < GMT_Offset)
  2326.         Seconds = 0;
  2327.     else
  2328.         Seconds = (ULONG)*t - GMT_Offset;
  2329.  
  2330.         /* Convert the seconds into time data. */
  2331.  
  2332.     Amiga2Date(Seconds,&ClockData);
  2333.  
  2334.         /* Convert the time data. */
  2335.  
  2336.     Time . tm_sec    = ClockData . sec;
  2337.     Time . tm_min    = ClockData . min;
  2338.     Time . tm_hour    = ClockData . hour;
  2339.     Time . tm_mday    = ClockData . mday;
  2340.     Time . tm_mon    = ClockData . month - 1;
  2341.     Time . tm_year    = ClockData . year - 1900;
  2342.     Time . tm_wday    = ClockData . wday;
  2343.  
  2344.         /* No daylight savings time info is provided. */
  2345.  
  2346.     Time . tm_isdst = 0;
  2347.  
  2348.         /* We will need to fill in the yday entry. */
  2349.  
  2350.     ClockData . mday    = 1;
  2351.     ClockData . month    = 1;
  2352.  
  2353.     Delta = Date2Amiga(&ClockData);
  2354.  
  2355.     Time . tm_yday = (Seconds - Delta) / (24 * 60 * 60) + 1;
  2356.  
  2357.         /* Clean up if necessary. */
  2358.  
  2359.     if(CloseIt)
  2360.     {
  2361.         CloseLibrary(UtilityBase);
  2362.  
  2363.         UtilityBase = NULL;
  2364.     }
  2365.  
  2366.     return(&Time);
  2367. }
  2368.  
  2369.     /* stat(const char *file,struct stat *st):
  2370.      *
  2371.      *    Get information on a file.
  2372.      */
  2373.  
  2374. int
  2375. stat(const char *file,struct stat *st)
  2376. {
  2377.     BPTR FileLock;
  2378.  
  2379.         /* Try to get a lock on the file. */
  2380.  
  2381.     if(FileLock = Lock((STRPTR)file,ACCESS_READ))
  2382.     {
  2383.         STATIC char    Volume[256],
  2384.                 Comment[80];
  2385.  
  2386.         struct FileInfoBlock __aligned    FileInfo;
  2387.         struct InfoData __aligned    InfoData;
  2388.  
  2389.             /* Get information on file and filing system. */
  2390.  
  2391.         if(Examine(FileLock,&FileInfo) && Info(FileLock,&InfoData))
  2392.         {
  2393.             unsigned short mode = 0;
  2394.  
  2395.                 /* Try to get the name of the volume. */
  2396.  
  2397.             if(!NameFromLock(FileLock,Volume,256))
  2398.                 Volume[0] = 0;
  2399.             else
  2400.             {
  2401.                 WORD i;
  2402.  
  2403.                     /* Chop off everything after the colon. */
  2404.  
  2405.                 for(i = 0 ; i < 256 ; i++)
  2406.                 {
  2407.                     if(Volume[i] == ':')
  2408.                     {
  2409.                         Volume[i + 1] = 0;
  2410.  
  2411.                         break;
  2412.                     }
  2413.                 }
  2414.             }
  2415.  
  2416.             UnLock(FileLock);
  2417.  
  2418.                 /* Build the protection bits. */
  2419.  
  2420.             if(!(FileInfo . fib_Protection & FIBF_EXECUTE))
  2421.                 mode |= S_IEXECUTE;
  2422.  
  2423.             if(!(FileInfo . fib_Protection & FIBF_DELETE))
  2424.                 mode |= S_IDELETE;
  2425.  
  2426.             if(!(FileInfo . fib_Protection & FIBF_READ))
  2427.                 mode |= S_IREAD;
  2428.  
  2429.             if(!(FileInfo . fib_Protection & FIBF_WRITE))
  2430.                 mode |= S_IWRITE;
  2431.  
  2432.             if(!(FileInfo . fib_Protection & FIBF_ARCHIVE))
  2433.                 mode |= S_IARCHIVE;
  2434.  
  2435.             if(FileInfo . fib_Protection & FIBF_PURE)
  2436.                 mode |= S_IPURE;
  2437.  
  2438.             if(FileInfo . fib_Protection & FIBF_SCRIPT)
  2439.                 mode |= S_ISCRIPT;
  2440.  
  2441.                 /* Keep the comment. */
  2442.  
  2443.             strcpy(Comment,FileInfo . fib_Comment);
  2444.  
  2445.                 /* Fix the time if necessary. */
  2446.  
  2447.             if(!TimerBase)
  2448.                 UpdateTime(NULL);
  2449.  
  2450.                 /* Fill in the data. */
  2451.  
  2452.             st -> st_mode    = mode;
  2453.             st -> st_ino    = FileInfo . fib_DiskKey;
  2454.             st -> st_dev    = InfoData . id_DiskType;
  2455.             st -> st_rdev    = Volume;
  2456.             st -> st_nlink    = FileInfo . fib_DirEntryType == ST_SOFTLINK || FileInfo . fib_DirEntryType == ST_LINKDIR || FileInfo . fib_DirEntryType == ST_LINKFILE;
  2457.             st -> st_uid    = FileInfo . fib_OwnerUID;
  2458.             st -> st_gid    = FileInfo . fib_OwnerGID;
  2459.             st -> st_size    = FileInfo . fib_Size;
  2460.             st -> st_atime    = GMT_Offset + (FileInfo . fib_Date . ds_Days * 24 * 60 + FileInfo . fib_Date . ds_Minute) * 60 + FileInfo . fib_Date . ds_Tick / TICKS_PER_SECOND;
  2461.             st -> st_mtime    = st -> st_atime;
  2462.             st -> st_ctime    = st -> st_atime;
  2463.             st -> st_type    = FileInfo . fib_DirEntryType;
  2464.             st -> st_comment= Comment;
  2465.  
  2466.                 /* Success. */
  2467.  
  2468.             return(0);
  2469.         }
  2470.  
  2471.         UnLock(FileLock);
  2472.     }
  2473.  
  2474.         /* What else should I choose? */
  2475.  
  2476.     errno = _OSERR = EIO;
  2477.  
  2478.     return(-1);
  2479. }
  2480.